문제 설명

빙고는 NxN 크기의 게임 보드 칸에 1부터 NxN까지의 자연수를 중복 없이 하나씩 적은 후 숫자를 하나씩 지워나가는 게임입니다. 이때, 가로, 세로, 대각선 방향으로 한 줄에 적힌 숫자를 모두 지울 경우 빙고를 1개 만들었다고 합니다. 다음은 4X4 크기의 게임 보드를 이용해 게임을 진행한 예시입니다.

image

위와 같이 각 칸에 숫자가 적혀 있을 때, 위 게임 보드에서 순서대로 지운 숫자가 [14,3,2,4,13,1,16,11,5,15]인 경우 아래와 같이 빙고 3개가 만들어집니다.

image

빙고 게임 보드에 적힌 숫자가 담겨있는 배열 board, 게임 보드에서 순서대로 지운 숫자가 들어있는 배열 nums가 매개변수로 주어질 때, board에서 nums에 들어있는 숫자를 모두 지우면 몇 개의 빙고가 만들어지는지 return하도록 solution함수를 완성해주세요.

제한사항

  • board는 게임 보드 칸에 적힌 숫자를 뜻하는 NxN크기의 2차원 배열이며, N은 2 이상 500이하의 자연수입니다.
  • board의 각 칸에는 1 이상 NxN이하의 자연수가 중복 없이 하나씩 들어있습니다.
  • nums는 board에서 지울 숫자가 들어있는 배열이며, 길이는 1 이상 NxN이하입니다.
  • nums에 들어있는 숫자는 1 이상 NxN이하의 자연수이며, 중복된 수가 들어있지 않습니다.

입출력 예

board nums result
[[11,13,15,16],[12,1,4,3],[10,2,7,8],[5,14,6,9]] [14,3,2,4,13,1,16,11,5,15] 3
[[6,15,17,14,23],[5,12,16,13,25],[21,4,2,1,22],[10,20,3,18,8],[11,9,19,24,7]] [15,7,2,25,9,16,12,18,5,4,10,13,20] 2
입출력 예 설명

입출력 예 #1 문제의 예시와 같습니다.

입출력 예 #2 다음 그림과 같이 2개의 빙고가 만들어집니다. image

나의 풀이

첫번째 풀이

소스

def check_bingo_horizontal(N, row, board):
    for i in range(N):
        if board[row][i] != -1:
            return False
    return True


def check_bingo_vertical(N, col, board):
    for i in range(N):
        if board[i][col] != -1:
            return False
    return True


def check_bingo_diagonal(N, board):
    for i in range(N):
        if board[i][i] != -1:
            return False
    return True


def check_bingo_diagonal_reverse(N, board):
    max_idx = N - 1
    for i in range(N):
        if board[i][max_idx - i] != -1:
            return False
    return True


def solution(board, nums):
    answer = 0

    bingo_hashboard = {}
    N = len(board)
    for row in range(N):
        for col in range(N):
            bingo_hashboard[board[row][col]] = (row, col)

    for num in nums:
        row, col = bingo_hashboard[num]

        board[row][col] = -1

        # 가로 체크
        if check_bingo_horizontal(N, row, board):
            answer += 1

        # 세로 체크
        if check_bingo_vertical(N, col, board):
            answer += 1

        # 대각선 체크 - 대각선 체크는 대각선 가능 유무도 판단한다
        if row == col and check_bingo_diagonal(N, board):
            answer += 1

        # 역 대각선 체크 - 대각선 체크는 대각선 가능 유무도 판단한다
        if row + col == N - 1 and check_bingo_diagonal_reverse(N, board):
            answer += 1

    return answer

설명

  • 일단, 빙고를 위한 숫자값이 들어왔을 때 (nums 순회) 그 해당 숫자가 어느위치에 있는지 빠르게 찾아가는것이 관건. (중복된 수가 들어오지 않기 때문에 따로 예외처리 할 필요는 없다.)
  • 그래서 bingo_hashboard라고 딕셔너리를 만들어 해당 값에 대한 위치정보를 담아둔다. {14:(0,3), 18:(3,3)…}
  • nums를 순회하면서 각 값에대한 해당 위치를 딕셔너리를 이용해 빠르게 찾고, 해당 위치값을 기반으로 빙고가 되었는지 체크한다.
  • 각 빙고를 체크하는 것은 함수화 시켜서 가로, 세로, 대각선, 역대각선 이렇게 처리하였다.

결과

통과

리뷰

  • 전체적으로 잘 작성하셨습니다. :) 실수하신 곳 한 부분만 수정하면 될 것 같습니다.
  • 시간복잡도는 전처리 하는 부분이 n^2이기 때문에 O(n^2)이 맞습니다. :)
  • 해당 부분은 for 루프 바깥으로 빼도 정상 동작하는 것 같습니다. :)

    for num in nums:
      row, col = bingo_hashboard[num]
    
      board[row][col] = -1
    
      # 가로 체크
      if check_bingo_horizontal(N, row, board):
          answer += 1
    
      # 세로 체크
      if check_bingo_vertical(N, col, board):
          answer += 1
    
    # 대각선 체크 - 대각선 체크는 대각선 가능 유무도 판단한다
    if check_bingo_diagonal(N, board):
      answer += 1
    
    # 역 대각선 체크 - 대각선 체크는 대각선 가능 유무도 판단한다
    if check_bingo_diagonal_reverse(N, board):
      answer += 1

스터디 리더의 풀이

def solution(board, nums):
    n = len(board) # board의 길이
    nums = set(nums)
    row_list = [0] * n
    col_list = [0] * n
    left_diagonal = 0
    right_diagonal = 0

    for i in range(n): # O(n)
        for j in range(n): # O(n)
            if board[i][j] in nums: # O(1)
                board[i][j] = 0
                row_list[i] += 1
                col_list[j] += 1

                if i == j:
                    left_diagonal += 1
                if n - 1 - i == j:
                    right_diagonal += 1

    answer = 0
    answer += sum([1 for i in row_list if i == n]) # 세로
    answer += sum([1 for i in col_list if i == n]) # 가로
    answer += 1 if left_diagonal == n else 0 # 왼쪽 대각선
    answer += 1 if right_diagonal == n else 0 # 오른쪽 대각선

    return answer

분석

  • 스터디 리더님의 풀이는 나처럼 nums를 순회하는 것이 아니라 애초에 정답을 처음부터 다 기록을 해두는 아이디어이다.
  • 빙고판을 순회하면서 불려진 값이 있으면 해당 값을 체크하는데, 여기서 rowlist와 collist를 각각 따로두어서 나온 개수만큼 관리를 하고, 이 rowlist, collist가 n만큼 개수가 되면 빙고가 완성되었다고 보는 방식.
  • 비슷한 방식으로 leftdiagonal과 rightdiagonal의 변수를 두어서 대각선의 나온 개수값을 체크한다.
  • 그래서 이렇게 빙고판을 다 돌고난 다음, 각각 rowlist와 collist, leftdiagonal, rightdiagonal을 통해 빙고 개수를 체크.